Skip to content

fix(renderer): classify and format authoring failures at their source - #396

Draft
tt-a1i wants to merge 2 commits into
mainfrom
codex/legacy-render-diagnostics
Draft

tt-a1i wants to merge 2 commits into
mainfrom
codex/legacy-render-diagnostics

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Problem and value

On main 6db72a9, node archify/bin/archify.mjs render architecture /no/such.json /tmp/diagram.html exits 1 with a raw Node stack. A valid-schema diagram with an overwide node label does the same, even though its renderer already attaches a layout diagnostic. A failed output write can also be reported as input/read by the JSON boundary because it guesses the operation from EISDIR/EACCES.

Classify read, JSON parse, and output filesystem failures where those operations occur. Human renderer failures now format attached diagnostics with their existing rule codes and supported repairs; an unexpected implementation exception retains its stack and exit 1. This is a narrow defect with a concrete reproduction, so it needs no separate planning issue.

Stability impact

  • Shared behavior: the common load/write path and diagnostic boundary used by architecture, workflow, sequence, dataflow, and lifecycle renderers. Public render and direct renderer scripts are covered.
  • Preserve schema/layout acceptance, successful artifact bytes, stdout output-path lines, non-zero failure exits, output alias guards, validate --json/deliver --json receipt structure, and standalone doctor startup. The public CLI source is unchanged. No new flag, schema, geometry, or Viewer change.
  • Expected filesystem errors receive input/read or output/write at the actual operation, including parent-directory creation. JSON parse errors are classified only around JSON.parse. Existing classified output-path errors keep their own code. Unexpected implementation failures are not guessed to be malformed JSON or unreadable input.
  • The JSON stderr transport block is unchanged. This is separate from the incomplete pipe-write problem in fix(renderer): flush complete failure diagnostics before exiting #351/fix(diagnostics): stop truncating large renderer receipts on a pipe #374; integrate one of those transport fixes independently.
  • Rendering still writes directly to its requested target; this PR does not claim atomic render writes. deliver remains the interface that preserves the prior artifact until verification and commit succeed.

Tests run

Base 6db72a9aea3d0f67a6a034e41f8a5491476a11c1; current candidate 80187faf511740005c8982e4a2514f132e08e40b. Local macOS, official Node 22.23.2. The working tree tested is identical to this commit.

  • node --test archify/test/render-failure-diagnostics.test.mjs archify/test/repair-receipt.test.mjs archify/test/cli-output-types.test.mjs: 34 passed, 0 failed, 0 skipped.
  • New regression cases reproduce both review blockers on the previously reviewed code. They cover a recorded layout problem followed by an unrelated exception, empty attached diagnostics, preservation of classified failures, and writeDiagram receiving an undefined output path in human/JSON modes. A formatter consistency test covers the non-blocking review suggestion without adding a renderer dependency to standalone doctor.
  • npm test from archify/: 1360 total; 1312 passed, 1 failed, 47 skipped. The only failure is checked-in MCO artifacts are byte-reproducible from the pinned repository revision; the same focused test fails on clean base 6db72a9. This is not a green full-suite claim. Optional/browser skips remain skips. The complete suite includes the standalone doctor regressions.
  • Extracted the rebuilt ZIP outside the repository without node_modules; all 15 render-failure tests passed.
  • ZIP rebuilt twice with identical bytes. The 79-entry inventory is unchanged; relative to reviewed head bfb7603, only renderers/shared/cli.mjs and renderers/shared/diagnostics.mjs change in the archive. git diff --check passed.
  • Earlier fixed-input five-mode HTML byte comparisons at bfb7603 remain historical evidence: this revision changes only failure guards and diagnostic selection, with successful public/direct output contracts retested above.
  • New-head hosted CI is running; inspect the PR Checks for its final result. Earlier CI runs are not evidence for this revised head.

Review follow-up

Addresses the two classification findings from @sunsunsun-java: recorded diagnostics are used only when the final exception has nonempty attached diagnostics; otherwise the receipt reports internal/unclassified. Read/write classification now requires filesystem code, syscall, and numeric errno, preserving implementation errors and existing classified path guards. The formatter suggestion is covered by a consistency regression while retaining standalone doctor startup.

Visual evidence

Not applicable. Only failure presentation/classification changes. The five-mode successful HTML comparison is byte-identical; no rendered appearance, interaction, or geometry is changed.

Generated artifacts

archify.zip rebuilt with official Node 22.23.2. All 79 archive entries are retained; changed entries are only references/delivery-contract.md, renderers/shared/cli.mjs, and renderers/shared/diagnostics.mjs. No gallery, examples, or other generated content changed because their rendered bytes remain identical.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sunsunsun-java

Copy link
Copy Markdown
Collaborator

审核中发现两个错误分类边界还需要处理:

1. 真正的程序错误可能被前面的诊断掩盖

如果渲染过程中先记录了一个布局问题,随后代码本身又发生意外异常,当前 JSON receipt 只会显示前面的布局问题,看不到真正导致程序失败的内部错误。

这样用户可能会一直修改图表,但实际上需要修复的是程序代码。

建议调整为:只有最终抛出的异常本身带有明确诊断时,才使用已记录的诊断;否则应报告 internal/unclassified,保留真正的内部错误。

2. 部分程序错误会被误报成“输出路径不可写”

现在只要异常带有字符串形式的 codethrowOutputError() 就会把它归类为 output/write。但 Node 自身的一些程序错误也有 code,例如参数类型错误。

例如 outPath 意外变成 undefined 时,本来应该显示程序堆栈,当前却会告诉用户“请选择可写的 HTML 路径”。这个建议与真正原因无关,也会隐藏实现缺陷。

建议只把确定来自文件系统操作的异常归类为 output/write,例如检查 syscallerrno;其他异常继续保留原始堆栈。

非阻塞建议

diagnostics.mjs 新增的 formatDiagnostics() 与 CLI 中已有的实现基本相同。以后修改其中一处时,两边的输出格式可能不一致。

这项不阻塞当前修复。如果不方便抽成共享模块,建议至少增加一致性测试,同时继续保证 doctor 在 renderer 文件缺失时仍能正常启动。

本地聚焦回归 31/31 通过,GitHub 最终头提交的 Node 18/20/22/24、三平台包冒烟和 ZIP 新鲜度检查也均通过;上面两个问题属于当前测试没有覆盖到的异常组合。

NaCr05 commented Sep 14, 2026

Copy link
Copy Markdown

Hi @tt-a1i — following up on the workflow library proposal in #222 to coordinate the diagnostic entrypoint.

At 80187faf511740005c8982e4a2514f132e08e40b, shared/cli.mjs still installs the process-level boundary at module initialization, and the workflow compiler imports that module for SVG helpers. The new human-mode handler makes it especially useful to keep installation explicit for CLI use before adding an in-process library entrypoint.

Would you prefer moving installation into loadDiagram() (or an explicit CLI bootstrap) here, or handling that as a small preparatory follow-up after #396 lands? I can take the follow-up and host-isolation regressions while preserving this PR's input/output error classification. The stderr transport work in #351/#374 would remain separate.

I have a private experiment on a07fa1d5 that moves initialization into the loader and preserves the five renderers' successful output and tested failure diagnostics; its results and limitations are in the linked comment. I have not tested that change against this PR's head yet. The broader workflow adapter remains subject to agreement with you and joesaby in #222.

NaCr05 commented Sep 15, 2026

Copy link
Copy Markdown

Hi @tt-a1i#418 is now synchronized with main d15010a at 8ae0d45. The PR still contains only the import-isolation fix, its two test files, and the ZIP; its diff against current main is byte-for-byte identical to the previously validated patch.

I propose landing #418 first, then updating #396 on top. The import-side-effect fix is independently useful and does not change this PR's error classifications. When updating #396, please preserve boundary installation at the start of loadDiagram(); the two standalone diagnostic probes in render-failure-diagnostics.test.mjs need to call installRendererDiagnosticBoundary() explicitly because they bypass the loader. Their assertions can stay intact. The combined ZIP should then be rebuilt and #396's checks rerun.

The earlier local rehearsal against your unchanged head 80187fa, with those two probe adaptations, passed 28 targeted checks. That remains historical compatibility evidence, not a full test of #396 merged with today's main. For the synchronized #418 head, Linux Node 22.23.2 full tests pass: 1333 passed, 0 failed, 48 skipped; ZIP freshness also passes. New-head CI is running.

Does this order work for you, or would you prefer #396 first? If #396 should land first, I can adapt #418 afterward, including the explicit probe initialization. #418 remains Draft pending that coordination.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants